
import { _decorator, Component, Node, Sprite, instantiate, resources, Label, math, Prefab, Graphics, Vec2, Vec3, Button, find, Tween, sys, UI, UITransform, Toggle, Slider, ProgressBar } from 'cc';
const { ccclass, property } = _decorator;
// 
import { AStar, Point } from "./AStar";
/**
 * Predefined variables
 * Name = AStarTestMore
 * DateTime = Sun Mar 27 2022 10:26:49 GMT+0800 (中国标准时间)
 * Author = lamd
 * FileBasename = AStarTestMore.ts
 * FileBasenameNoExtension = AStarTestMore
 * URL = db://assets/Scripts/AStarTestMore.ts
 * ManualUrl = https://docs.cocos.com/creator/3.4/manual/zh/
 *
 */



class Tile {
    point: Point;
    node: Node;
    lb: Label;
    sp: Sprite;
}

@ccclass('AStarTestMore')
export class AStarTestMore extends Component {

    mapData: number[][] = [];

    from: Point; //起始点
    to: Point; //终点

    rowMax: number = 100;
    colMax: number = 100;
    row: number;//行 （max = 100)
    col: number;//列（max = 100)

    aStarProg: AStar;

    // [2]
    // @property
    // serializableDummy = 0;
    path: Point[] = [];
    tiles: Tile[][] = [];
    tilePool: Tile[] = [];

    isShowCoor: boolean;
    xiePassAble: boolean;

    tilePfb: Prefab;
    loading: Node;
    mapNode: Node;
    nodePlayer: Node;
    tipsNode: Node;
    lbGridNum: Label;
    lbRateNum: Label;
    lbConsumeTime: Label; // 寻路消耗时间
    sliderGrid: Slider; // 控制网格数目的slider
    slidRate: Slider;
    togSkewCross: Toggle;


    baseW: number; // baseW
    tileW: number; // tileW = baseW*10/col // 当时是按10列设计的
    obstacleRate: number = 25; // 障碍概率

    pathTween: Tween<Node>;
    pathTweenFinished: boolean;

    showTips() {
        this.tipsNode.setPosition(0, -100);
        this.tipsNode.active = true;
        new Tween(this.tipsNode).by(2, { position: new Vec3(0, 200) }).call(() => {
            this.tipsNode.active = false;
        }).start();
    }

    calcSearchTime() {
        const t1 = new Date().getMilliseconds();
        this.path = this.aStarProg.run(this.from, this.to);
        const t2 = new Date().getMilliseconds();

        this.lbConsumeTime.string = "消耗时间:" + (t2 - t1) + "ms"

        const row = this.tiles.length;
        const col = this.tiles[0].length;
        console.log("方块数目：" + row * col);
        // if (sys.platform == sys.Platform.ANDROID) {
        //     console.log("安卓平台");
        // }
        // else if (sys.platform == sys.Platform.WIN32) {
        //     var dt = new Date();
        //     console.log("WIN32平台" + dt.getTime());
        // }
        // else if (sys.platform == sys.Platform.DESKTOP_BROWSER) {
        //     console.log("浏览器 寻路时间：" + (dt.getMilliseconds() - t1) + "ms");
        // }
    }
    // 开始寻路
    onBtnStart() {
        if (this.pathTween && !this.pathTweenFinished)
            this.pathTween.stop();

        this.updateTiles();

        console.time('SearchTime');
        this.calcSearchTime();
        console.timeEnd('SearchTime');

        if (this.path === undefined) {
            this.showTips();
            return;
        }

        this.pathTween = new Tween(this.nodePlayer)

        let self = this;
        this.pathTweenFinished = false;

        for (let i = 1; i < this.path.length; i++) {
            let rc: Point = this.path[i]; // 行列坐标
            let pos: Vec3 = this.getCoor(rc.y, rc.x)

            this.pathTween.to(0.2, { position: pos });
            if (i != this.path.length - 1)
                this.pathTween.call(() => {
                    self.tiles[rc.y][rc.x].sp.color = math.Color.RED;
                })
            else
                this.pathTween.call(() => {
                    this.pathTweenFinished = true;
                })
        }

        this.pathTween.union().start();
    }

    onBtnOpenCoor() {
        this.isShowCoor = !this.isShowCoor;
        this.updateTiles();
    }

    onTogSkewCross(toggle: Toggle) {
        this.aStarProg.changeXiePassAble(toggle.isChecked);
    }

    onTouchEndSlider() {
        const r = Math.floor(this.sliderGrid.progress * this.rowMax);
        const c = Math.floor(this.sliderGrid.progress * this.colMax);
        this.randomMapData(r, c);
        this.loadMapData();
    }

    onSlidGrid(slider: Slider) {
        // console.log("slider.progress:" + slider.progress);
        this.checkSlider(slider);
    }

    onSlidRate(slider: Slider) {
        this.obstacleRate = Math.floor(slider.progress * 100);
        this.lbRateNum.string = this.obstacleRate.toString();
    }

    checkSlider(slider) {
        if (slider.progress <= 0.1)
            slider.progress = 0.1;

        const c = Math.floor(slider.progress * this.colMax);
        const r = Math.floor(slider.progress * this.rowMax);
        this.lbGridNum.string = (c * r).toString();

    }

    total: number;
    count: number;
    progressBar: ProgressBar;
    lbProgress: Label;

    start() {
        this.isShowCoor = false;
        this.xiePassAble = false;

        this.nodePlayer = this.node.getChildByName("nodePlayer");
        this.tipsNode = this.node.getChildByName("lbTips");

        this.baseW = this.nodePlayer.getComponent(UITransform).contentSize.width; // 一开始是按10*10设计的
        console.log("this.baseW" + this.baseW);

        const canvas: Node = find("Canvas");
        this.loading = canvas.getChildByName("loading")
        this.mapNode = this.node.getChildByName("NodeTiles");

        this.progressBar = this.loading.getComponentInChildren(ProgressBar);
        this.lbProgress = this.loading.getChildByName("lbProgress").getComponent(Label)

        this.total = this.rowMax * this.colMax;

        //加载所有方块
        resources.load("AStar/pfbTile", Prefab, (err, prefab) => {
            this.tilePfb = prefab;
            let y = 0;
            let x = 0;
            const xBorder = 50;
            this.schedule(() => {
                if (y < this.rowMax) {

                    if (!this.tiles[y])
                        this.tiles[y] = [];

                    if (x >= xBorder) {
                        while (x < this.colMax) {
                            this.newTile(prefab, x, y)
                            x++;
                        }
                    }
                    else
                        while (x < xBorder) {
                            this.newTile(prefab, x, y)
                            x++;
                        }

                    if (x >= this.colMax) {
                        x = 0;
                        y++;
                    }

                    const progress: number = y / this.rowMax;
                    this.lbProgress.string = Math.floor(progress * 100).toString() + "%";
                    this.progressBar.progress = progress;
                    // console.log(this.lbProgress.string);

                    if (y == this.rowMax) {
                        // console.log("加载完毕");
                        this.loaded();
                    }
                }
            })
        });

        this.lbConsumeTime = canvas.getChildByName("lbConsumeTime").getComponent(Label);
        const btnStart: Button = canvas.getChildByName("BtnStart").getComponent(Button);

        const btnRandom: Button = canvas.getChildByName("BtnRandorm").getComponent(Button);
        const btnOpenCoor: Button = canvas.getChildByName("BtnOpenCoor").getComponent(Button);

        this.sliderGrid = canvas.getChildByName("SliderGride").getComponent(Slider); // 重新生成格子数
        this.togSkewCross = canvas.getChildByName("Toggle").getComponent(Toggle); // 是否斜穿
        this.slidRate = canvas.getChildByName("SliderRate").getComponent(Slider); // 障碍概率

        this.lbGridNum = this.sliderGrid.node.getChildByName("lbNum").getComponent(Label);
        this.lbRateNum = this.slidRate.node.getChildByName("lbNum").getComponent(Label);
        const slider: Slider = this.sliderGrid.node.getComponent(Slider);
        slider.handle.node.on(Node.EventType.TOUCH_END, this.onTouchEndSlider, this)
        slider.handle.node.on(Node.EventType.TOUCH_CANCEL, this.onTouchEndSlider, this)

        this.togSkewCross.node.on('toggle', this.onTogSkewCross, this);
        this.sliderGrid.node.on('slide', this.onSlidGrid, this);
        this.slidRate.node.on('slide', this.onSlidRate, this);

        btnStart.node.on(Button.EventType.CLICK, this.onBtnStart, this);
        btnRandom.node.on(Button.EventType.CLICK, this.onRandomMap, this);
        btnOpenCoor.node.on(Button.EventType.CLICK, this.onBtnOpenCoor, this);
    }

    newTile(prefab: Prefab, x: number, y: number) {
        let tile: Tile = new Tile();
        const tileNode = instantiate(prefab);
        this.mapNode.addChild(tileNode);
        tileNode.active = false;

        let lb: Label = tileNode.getComponentInChildren(Label);
        let sp: Sprite = tileNode.getComponent(Sprite);

        tile.node = tileNode;
        tile.sp = sp;
        tile.lb = lb;
        tile.point = { x: x, y: y };

        this.tiles[y][x] = tile;
    }

    // 加载完成，初始化地图
    loaded() {
        this.loading.active = false;

        this.aStarProg = new AStar();

        this.randomMapData(10, 10);
        this.loadMapData();

        this.initUIValue();
    }

    initUIValue() {
        this.checkSlider(this.sliderGrid);
        this.aStarProg.changeXiePassAble(this.togSkewCross.isChecked);

        this.lbRateNum.string = this.obstacleRate.toString();
        this.slidRate.progress = this.obstacleRate / 100;

        this.lbConsumeTime.string = "消耗时间:0ms"
    }

    // 由行列得到坐标
    getCoor(row: number, col: number): Vec3 {
        return new Vec3((-180 + this.tileW / 2 + (col) * this.tileW), 180 - (this.tileW / 2 + (row) * this.tileW));
    }

    drawLine(row: number, column: number) {
        const g = this.getComponentInChildren(Graphics);
        g.clear();

        for (let i = 1; i < row; i++) {
            g.moveTo(-180, 180 - (i * this.tileW));
            g.lineTo(180, 180 - (i * this.tileW));
        }

        for (let i = 1; i < column; i++) {
            g.moveTo(-180 + (i * this.tileW), 180);
            g.lineTo(-180 + (i * this.tileW), -180);
        }

        g.close();
        g.stroke();
        g.fill();
    }

    // 随机按钮事件
    onRandomMap() {
        this.randomMapData(this.row, this.col, true);
        this.loadMapData();
    }

    // 随机地图数据
    randomMapData(row?: number, col?: number, isNewEnd?: boolean) {
        if (col && row) {
            this.row = row;
            this.col = col;
        }

        this.mapData = []

        for (let y = 0; y < this.row; y++) {
            for (let x = 0; x < this.col; x++) {
                if (this.mapData[y] === undefined)
                    this.mapData[y] = [];

                this.mapData[y][x] = Math.floor(Math.random() * 100) < this.obstacleRate ? 1 : 0;
            }
        }
        //100*100无障碍    9.501953125 ms

        // arr = [
        //     [0, 0, 0, 1, 0, 0, 0, 0, 0, 0],
        //     [0, 0, 0, 1, 0, 0, 0, 0, 0, 0],
        //     [0, 0, 0, 1, 0, 0, 0, 1, 0, 0],
        //     [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
        //     [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
        //     [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
        //     [1, 1, 1, 1, 0, 0, 1, 0, 0, 0],
        //     [0, 0, 0, 1, 0, 0, 1, 0, 0, 0],
        //     [0, 0, 0, 1, 0, 0, 1, 0, 0, 0],
        //     [0, 0, 0, 1, 0, 0, 0, 0, 0, 0],
        // ]

        this.from = { x: 1, y: 1 };
        this.to = { x: this.col - 1, y: this.row - 1 };
        this.mapData[1][1] = 0;
        this.mapData[this.to.y][this.to.x] = 0;

        this.tileW = this.baseW * 10 / (this.col);

        while (isNewEnd) {
            this.to = { x: Math.floor(Math.random() * (this.col)), y: Math.floor(Math.random() * (this.row)) }
            // console.log(this.to.x, this.to.y);

            if (this.from.x != this.to.x && this.from.y != this.to.y && this.mapData[this.to.y][this.to.x] == 0)
                isNewEnd = false;
        }

        this.aStarProg.setData(this.mapData);
    }

    // recycleTile() {
    //     if (!this.tiles[0])
    //         return;

    //     for (let y = 0; y < this.tiles.length; y++) {
    //         for (let x = 0; x < this.tiles[0].length; x++) {
    //             this.tiles[y][x].node.active = false;
    //             this.tilePool.push(this.tiles[y][x]);
    //         }
    //     }

    //     this.tiles = [];
    // }

    clearTiles() {
        for (let y = 0; y < this.tiles.length; y++) {
            for (let x = 0; x < this.tiles[0].length; x++) {
                if (this.tiles[y][x]) {
                    if (this.tiles[y][x].node)
                        this.tiles[y][x].node.active = false;
                }
                else
                    console.log("无效x,y：", x, y);
            }
        }
    }

    // 载入地图
    loadMapData() {
        if (this.pathTween)
            this.pathTween.stop();

        this.clearTiles();
        this.updateTiles();

        this.drawLine(this.row, this.col);

        this.nodePlayer.setPosition(this.getCoor(this.from.y, this.from.x));
        this.nodePlayer.getComponent(UITransform).setContentSize(this.tileW, this.tileW)
    }

    updateTile(tile: Tile) {
        if (!tile.point) return;

        const x = tile.point.x;
        const y = tile.point.y;

        tile.node.active = true;
        tile.node.setPosition(this.getCoor(y, x));
        // tile.node.getComponent(UITransform).setContentSize(this.tileW, this.tileW);
        const scl: number = this.tileW / this.baseW;
        tile.node.setScale(scl, scl);

        // tile.lb.string = this.isShowCoor ? x + "," + y : "";
        tile.lb.node.active = false;
        if (this.from.x === x && this.from.y === y) {
            tile.lb.node.active = true;
            tile.lb.string = "始";
            tile.sp.color = math.Color.GREEN;
        } else if (this.to.x === x && this.to.y === y) {
            tile.lb.node.active = true;
            tile.lb.string = "终";
            tile.sp.color = math.Color.GREEN;
        } else if (this.mapData[y][x] == 1) {
            tile.sp.color = math.Color.BLUE;
        }
        else
            tile.sp.color = math.Color.WHITE;
    }

    updateTiles() {
        for (let y = 0; y < this.col; y++)
            for (let x = 0; x < this.row; x++)
                this.updateTile(this.tiles[y][x]);
    }


}
